const { PrintReservation, PrintConfig, File, User } = require('../models')
const logger = require('../utils/logger')
const { v4: uuidv4 } = require('uuid')
const QRCode = require('qrcode')

class PrintReservationService {
  /**
   * 创建打印预约
   * @param {number} userId - 用户ID
   * @param {number} fileId - 文件ID
   * @param {Object} printOptions - 打印参数
   * @param {number} quantity - 打印份数
   * @returns {Promise<Object>} 预约记录
   */
  async createReservation(userId, fileId, printOptions, quantity = 1) {
    try {
      // 验证文件是否存在且属于用户
      const file = await File.findOne({
        where: {
          id: fileId,
          user_id: userId,
          status: 1
        }
      })

      if (!file) {
        throw new Error('文件不存在或无权限访问')
      }

      // 验证打印参数
      await this.validatePrintOptions(printOptions)

      // 计算积分消耗
      const pointsCost = await this.calculatePointsCost(file, printOptions, quantity)

      // 检查用户积分是否足够
      const user = await User.findByPk(userId)
      if (user.points < pointsCost) {
        throw new Error('积分不足，无法创建预约')
      }

      // 生成预约码
      const reservationCode = this.generateReservationCode()

      // 计算过期时间（24小时后）
      const expiresAt = new Date()
      expiresAt.setHours(expiresAt.getHours() + 24)

      // 创建预约记录
      const reservation = await PrintReservation.create({
        user_id: userId,
        file_id: fileId,
        reservation_code: reservationCode,
        print_options: printOptions,
        quantity,
        total_pages: (file.page_count || 1) * quantity,
        points_cost: pointsCost,
        status: 'pending',
        expires_at: expiresAt
      })

      // 扣除用户积分
      await user.decrement('points', { by: pointsCost })

      // 记录积分消费
      await this.recordPointsConsumption(userId, pointsCost, reservation.id)

      logger.info(`Print reservation created: ${reservation.id}`, {
        userId,
        fileId,
        reservationCode,
        pointsCost
      })

      return await this.getReservationDetail(reservation.id)
    } catch (error) {
      logger.error('Create print reservation failed:', error)
      throw error
    }
  }

  /**
   * 获取预约详情
   * @param {number} reservationId - 预约ID
   * @returns {Promise<Object>} 预约详情
   */
  async getReservationDetail(reservationId) {
    try {
      const reservation = await PrintReservation.findOne({
        where: { id: reservationId },
        include: [
          {
            model: User,
            as: 'user',
            attributes: ['id', 'nickname', 'phone']
          },
          {
            model: File,
            as: 'file',
            attributes: ['id', 'original_name', 'file_size', 'file_type', 'page_count', 'preview_url']
          }
        ]
      })

      if (!reservation) {
        throw new Error('预约记录不存在')
      }

      // 生成二维码
      const qrCodeUrl = await this.generateQRCode(reservation.reservation_code)

      return {
        id: reservation.id,
        reservationCode: reservation.reservation_code,
        printOptions: reservation.print_options,
        quantity: reservation.quantity,
        totalPages: reservation.total_pages,
        pointsCost: reservation.points_cost,
        status: reservation.status,
        storeLocation: reservation.store_location,
        notes: reservation.notes,
        reservedAt: reservation.reserved_at,
        expiresAt: reservation.expires_at,
        confirmedAt: reservation.confirmed_at,
        completedAt: reservation.completed_at,
        qrCodeUrl,
        user: reservation.user,
        file: reservation.file
      }
    } catch (error) {
      logger.error('Get reservation detail failed:', error)
      throw error
    }
  }

  /**
   * 获取用户预约列表
   * @param {number} userId - 用户ID
   * @param {number} page - 页码
   * @param {number} limit - 每页数量
   * @param {string} status - 状态筛选
   * @returns {Promise<Object>} 预约列表
   */
  async getUserReservations(userId, page = 1, limit = 20, status = null) {
    try {
      const offset = (page - 1) * limit
      const whereClause = { user_id: userId }
      
      if (status) {
        whereClause.status = status
      }

      const { count, rows } = await PrintReservation.findAndCountAll({
        where: whereClause,
        include: [
          {
            model: File,
            as: 'file',
            attributes: ['id', 'original_name', 'file_size', 'file_type', 'page_count', 'preview_url']
          }
        ],
        order: [['created_at', 'DESC']],
        limit,
        offset
      })

      const reservations = rows.map(reservation => ({
        id: reservation.id,
        reservationCode: reservation.reservation_code,
        printOptions: reservation.print_options,
        quantity: reservation.quantity,
        totalPages: reservation.total_pages,
        pointsCost: reservation.points_cost,
        status: reservation.status,
        reservedAt: reservation.reserved_at,
        expiresAt: reservation.expires_at,
        file: reservation.file
      }))

      return {
        reservations,
        pagination: {
          total: count,
          page,
          limit,
          pages: Math.ceil(count / limit)
        }
      }
    } catch (error) {
      logger.error('Get user reservations failed:', error)
      throw error
    }
  }

  /**
   * 验证预约码
   * @param {string} reservationCode - 预约码
   * @returns {Promise<Object>} 预约信息
   */
  async validateReservationCode(reservationCode) {
    try {
      const reservation = await PrintReservation.findOne({
        where: { reservation_code: reservationCode },
        include: [
          {
            model: User,
            as: 'user',
            attributes: ['id', 'nickname', 'phone']
          },
          {
            model: File,
            as: 'file',
            attributes: ['id', 'original_name', 'file_size', 'file_type', 'page_count']
          }
        ]
      })

      if (!reservation) {
        throw new Error('预约码不存在')
      }

      // 检查是否过期
      if (new Date() > reservation.expires_at) {
        await reservation.update({ status: 'expired' })
        throw new Error('预约已过期')
      }

      // 检查状态
      if (reservation.status === 'cancelled') {
        throw new Error('预约已取消')
      }

      if (reservation.status === 'completed') {
        throw new Error('预约已完成')
      }

      return {
        id: reservation.id,
        reservationCode: reservation.reservation_code,
        printOptions: reservation.print_options,
        quantity: reservation.quantity,
        totalPages: reservation.total_pages,
        status: reservation.status,
        user: reservation.user,
        file: reservation.file
      }
    } catch (error) {
      logger.error('Validate reservation code failed:', error)
      throw error
    }
  }

  /**
   * 确认预约（到店核销）
   * @param {string} reservationCode - 预约码
   * @param {string} storeLocation - 店铺位置
   * @returns {Promise<Object>} 确认结果
   */
  async confirmReservation(reservationCode, storeLocation = null) {
    try {
      const reservation = await this.validateReservationCode(reservationCode)

      if (reservation.status !== 'pending') {
        throw new Error('预约状态不正确')
      }

      // 更新预约状态
      await PrintReservation.update({
        status: 'confirmed',
        store_location: storeLocation,
        confirmed_at: new Date()
      }, {
        where: { reservation_code: reservationCode }
      })

      logger.info(`Reservation confirmed: ${reservationCode}`, { storeLocation })

      return await this.getReservationDetail(reservation.id)
    } catch (error) {
      logger.error('Confirm reservation failed:', error)
      throw error
    }
  }

  /**
   * 完成预约
   * @param {string} reservationCode - 预约码
   * @returns {Promise<Object>} 完成结果
   */
  async completeReservation(reservationCode) {
    try {
      const reservation = await this.validateReservationCode(reservationCode)

      if (!['confirmed', 'processing'].includes(reservation.status)) {
        throw new Error('预约状态不正确')
      }

      // 更新预约状态
      await PrintReservation.update({
        status: 'completed',
        completed_at: new Date()
      }, {
        where: { reservation_code: reservationCode }
      })

      logger.info(`Reservation completed: ${reservationCode}`)

      return await this.getReservationDetail(reservation.id)
    } catch (error) {
      logger.error('Complete reservation failed:', error)
      throw error
    }
  }

  /**
   * 取消预约
   * @param {number} reservationId - 预约ID
   * @param {number} userId - 用户ID
   * @returns {Promise<boolean>} 取消结果
   */
  async cancelReservation(reservationId, userId) {
    try {
      const reservation = await PrintReservation.findOne({
        where: {
          id: reservationId,
          user_id: userId
        }
      })

      if (!reservation) {
        throw new Error('预约记录不存在')
      }

      if (!['pending', 'confirmed'].includes(reservation.status)) {
        throw new Error('当前状态无法取消')
      }

      // 更新预约状态
      await reservation.update({ status: 'cancelled' })

      // 退还积分
      const user = await User.findByPk(userId)
      await user.increment('points', { by: reservation.points_cost })

      // 记录积分退还
      await this.recordPointsRefund(userId, reservation.points_cost, reservation.id)

      logger.info(`Reservation cancelled: ${reservationId}`, { userId })

      return true
    } catch (error) {
      logger.error('Cancel reservation failed:', error)
      throw error
    }
  }

  /**
   * 验证打印参数
   * @param {Object} printOptions - 打印参数
   */
  async validatePrintOptions(printOptions) {
    const requiredFields = ['paperSize', 'colorType', 'printQuality']
    
    for (const field of requiredFields) {
      if (!printOptions[field]) {
        throw new Error(`缺少必要的打印参数: ${field}`)
      }
    }

    // 验证参数值是否有效
    const configs = await PrintConfig.findAll({
      where: { is_active: true }
    })

    const configMap = {}
    configs.forEach(config => {
      if (!configMap[config.category]) {
        configMap[config.category] = []
      }
      configMap[config.category].push(config.value)
    })

    if (!configMap.paper_size?.includes(printOptions.paperSize)) {
      throw new Error('无效的纸张大小')
    }

    if (!configMap.color_type?.includes(printOptions.colorType)) {
      throw new Error('无效的颜色类型')
    }

    if (!configMap.print_quality?.includes(printOptions.printQuality)) {
      throw new Error('无效的打印质量')
    }
  }

  /**
   * 计算积分消耗
   * @param {Object} file - 文件信息
   * @param {Object} printOptions - 打印参数
   * @param {number} quantity - 打印份数
   * @returns {Promise<number>} 积分消耗
   */
  async calculatePointsCost(file, printOptions, quantity) {
    try {
      // 基础积分（每页1积分）
      const basePoints = (file.page_count || 1) * quantity

      // 获取配置的倍数
      const configs = await PrintConfig.findAll({
        where: {
          is_active: true,
          value: {
            [require('sequelize').Op.in]: [
              printOptions.paperSize,
              printOptions.colorType,
              printOptions.printQuality,
              printOptions.bindingType
            ].filter(Boolean)
          }
        }
      })

      let multiplier = 1
      configs.forEach(config => {
        multiplier *= parseFloat(config.points_multiplier)
      })

      return Math.ceil(basePoints * multiplier)
    } catch (error) {
      logger.error('Calculate points cost failed:', error)
      // 返回默认值
      return (file.page_count || 1) * quantity
    }
  }

  /**
   * 生成预约码
   * @returns {string} 预约码
   */
  generateReservationCode() {
    const timestamp = Date.now().toString(36)
    const random = Math.random().toString(36).substring(2, 8)
    return `PR${timestamp}${random}`.toUpperCase()
  }

  /**
   * 生成二维码
   * @param {string} reservationCode - 预约码
   * @returns {Promise<string>} 二维码URL
   */
  async generateQRCode(reservationCode) {
    try {
      const qrCodeData = JSON.stringify({
        type: 'print_reservation',
        code: reservationCode,
        timestamp: Date.now()
      })

      const qrCodeUrl = await QRCode.toDataURL(qrCodeData, {
        width: 200,
        margin: 2,
        color: {
          dark: '#000000',
          light: '#FFFFFF'
        }
      })

      return qrCodeUrl
    } catch (error) {
      logger.error('Generate QR code failed:', error)
      return null
    }
  }

  /**
   * 记录积分消费
   * @param {number} userId - 用户ID
   * @param {number} points - 积分数量
   * @param {number} reservationId - 预约ID
   */
  async recordPointsConsumption(userId, points, reservationId) {
    try {
      const pointsService = require('./pointsService')
      
      await pointsService.deductPoints(
        userId,
        points,
        'consume',
        `打印预约消费积分 - 预约ID: ${reservationId}`
      )
    } catch (error) {
      logger.error('Record points consumption failed:', error)
    }
  }

  /**
   * 记录积分退还
   * @param {number} userId - 用户ID
   * @param {number} points - 积分数量
   * @param {number} reservationId - 预约ID
   */
  async recordPointsRefund(userId, points, reservationId) {
    try {
      const pointsService = require('./pointsService')
      
      await pointsService.addPoints(
        userId,
        points,
        'activity',
        `取消打印预约退还积分 - 预约ID: ${reservationId}`
      )
    } catch (error) {
      logger.error('Record points refund failed:', error)
    }
  }

  /**
   * 获取打印配置
   * @returns {Promise<Object>} 打印配置
   */
  async getPrintConfigs() {
    try {
      const configs = await PrintConfig.findAll({
        where: { is_active: true },
        order: [['category', 'ASC'], ['sort_order', 'ASC']]
      })

      const configMap = {}
      configs.forEach(config => {
        if (!configMap[config.category]) {
          configMap[config.category] = []
        }
        configMap[config.category].push({
          value: config.value,
          displayName: config.display_name,
          description: config.description,
          pointsMultiplier: parseFloat(config.points_multiplier),
          isDefault: config.is_default
        })
      })

      return configMap
    } catch (error) {
      logger.error('Get print configs failed:', error)
      throw error
    }
  }

  /**
   * 清理过期预约
   * @returns {Promise<number>} 清理数量
   */
  async cleanupExpiredReservations() {
    try {
      const expiredReservations = await PrintReservation.findAll({
        where: {
          status: 'pending',
          expires_at: {
            [require('sequelize').Op.lt]: new Date()
          }
        }
      })

      let cleanedCount = 0
      for (const reservation of expiredReservations) {
        try {
          await reservation.update({ status: 'expired' })
          
          // 退还积分
          const user = await User.findByPk(reservation.user_id)
          if (user) {
            await user.increment('points', { by: reservation.points_cost })
            await this.recordPointsRefund(reservation.user_id, reservation.points_cost, reservation.id)
          }
          
          cleanedCount++
        } catch (error) {
          logger.warn(`Failed to cleanup expired reservation: ${reservation.id}`, error)
        }
      }

      logger.info(`Cleaned up ${cleanedCount} expired reservations`)
      return cleanedCount
    } catch (error) {
      logger.error('Cleanup expired reservations failed:', error)
      throw error
    }
  }
}

module.exports = new PrintReservationService()